using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.Network;

namespace OracleInternal.ServiceObjects
{
	internal class NotificationListener
	{
		internal bool m_bListenerStarted;

		private object m_syncObject;

		private Thread m_lsnrThread;

		internal OracleCommunication m_lsnrEP;

		private OraBufPool m_oraBufPoolForListener;

		internal static NotificationListener m_ntfLister = new NotificationListener();

		private NotificationListener()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationListener, OracleTraceFuncName.ctor);
			}
			m_bListenerStarted = false;
			m_syncObject = new object();
			m_oraBufPoolForListener = new OraBufPool(127);
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationListener, OracleTraceFuncName.ctor);
			}
		}

		internal static NotificationListener CreateListener()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationListener, OracleTraceFuncName.CreateListener);
			}
			try
			{
				return m_ntfLister;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationListener, OracleTraceFuncName.CreateListener);
				}
			}
		}

		internal bool Start(ref int portNo)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationListener, OracleTraceFuncName.Start);
			}
			bool result = false;
			try
			{
				if (!m_bListenerStarted)
				{
					lock (m_syncObject)
					{
						if (!m_bListenerStarted)
						{
							bool flag = portNo == -1;
							if (portNo <= 0 || !IsPortAvailable(portNo))
							{
								if (!flag)
								{
									throw new ArgumentException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.NTFN_PORT_NOT_AVAILABLE));
								}
								portNo = FindFreePort();
							}
							m_lsnrEP = new OracleCommunication(new ConOraBufPool(m_oraBufPoolForListener));
							string text = string.Empty;
							if (OracleDependencyImpl.m_bIsAddressConfigured && !string.IsNullOrWhiteSpace(OracleDependencyImpl.s_machineAddress))
							{
								text = OracleDependencyImpl.GetAddress(OracleDependencyImpl.s_machineAddress);
							}
							if (ProviderConfig.m_bTraceLevelNetwork)
							{
								Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.NotificationListener, OracleTraceFuncName.Start, "Notification Listener requested for : (address=" + text + ") (port=" + portNo + ")");
							}
							m_lsnrEP.Listen(text + ":" + portNo, !OracleDependencyImpl.m_bIsAddressConfigured);
							m_bListenerStarted = true;
							result = true;
						}
						m_lsnrThread = new Thread(new ThreadStart(ListenerThreadFunction));
						m_lsnrThread.IsBackground = true;
						m_lsnrThread.Start();
					}
				}
				return result;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationListener, OracleTraceFuncName.Start, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationListener, OracleTraceFuncName.Start);
				}
			}
		}

		internal void ListenerThreadFunction()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationListener, OracleTraceFuncName.ListenerThreadFunction);
			}
			try
			{
				while (true)
				{
					OracleNotificationManager.HandleNotification(new OracleCommunication(m_lsnrEP, null));
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationListener, OracleTraceFuncName.ListenerThreadFunction, ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationListener, OracleTraceFuncName.ListenerThreadFunction);
				}
			}
		}

		internal static bool IsPortAvailable(int portNo)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationListener, OracleTraceFuncName.IsPortAvailable);
			}
			bool result = true;
			try
			{
				TcpConnectionInformation[] activeTcpConnections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections();
				for (int i = 0; i < activeTcpConnections.Length; i++)
				{
					if (activeTcpConnections[i].LocalEndPoint.Port == portNo)
					{
						result = false;
						break;
					}
				}
				return result;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationListener, OracleTraceFuncName.IsPortAvailable, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationListener, OracleTraceFuncName.IsPortAvailable);
				}
			}
		}

		internal static int FindFreePort()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.NotificationListener, OracleTraceFuncName.FindFreePort);
			}
			try
			{
				TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 0);
				tcpListener.Start();
				int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
				tcpListener.Stop();
				return port;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.NotificationListener, OracleTraceFuncName.FindFreePort, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.NotificationListener, OracleTraceFuncName.FindFreePort);
				}
			}
		}
	}
}
